﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

using Microsoft.SharePoint;

namespace Actuant.Utility
{
    public static class SPLookupHelper
    {
        #region Public Methods

        /// <summary>
        /// The create list lookup field.
        /// </summary>
        /// <param name="displayName">
        /// The display name.
        /// </param>
        /// <param name="fieldName">
        /// The field name.
        /// </param>
        /// <param name="group">
        /// The group.
        /// </param>
        /// <param name="required">
        /// The required.
        /// </param>
        /// <param name="allowMultipleValues">
        /// The allow multiple values.
        /// </param>
        /// <param name="listWeb">
        /// The list web.
        /// </param>
        /// <param name="listName">
        /// The list name.
        /// </param>
        /// <param name="lookupListName">
        /// The lookup list name.
        /// </param>
        /// <param name="lookupField">
        /// The lookup field.
        /// </param>
        /// <returns>
        /// An instance of the newly created lookup field
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// </exception>
        public static SPFieldLookup CreateListLookupField(string displayName, string fieldName, string group, bool required, bool allowMultipleValues, SPWeb listWeb, string listName, string lookupListName, string lookupField)
        {
            SPLogger.LogToDeveloper(MethodBase.GetCurrentMethod().Name);

            SPList list = SPListHelper.GetList(listWeb, listName);
            SPList lookupList = SPListHelper.GetList(listWeb, lookupListName);

            if (list == null)
            {
                throw new ArgumentOutOfRangeException("listName", "Cannot find list with name " + listName);
            }

            if (lookupList == null)
            {
                throw new ArgumentOutOfRangeException("lookupListName", "Cannot find list with name " + lookupListName);
            }

            string internalName = list.Fields.AddLookup(fieldName, lookupList.ID, listWeb.ID, required);

            SPFieldLookup lookup = list.Fields.GetFieldByInternalName(internalName) as SPFieldLookup;

            if (lookup != null)
            {
                lookup.AllowMultipleValues = allowMultipleValues;
                lookup.LookupField = lookupField;
                lookup.Group = group;

                // Make the first item on the list the default value
                lookup.DefaultValue = "1;#";
                if (!String.IsNullOrEmpty(displayName))
                {
                    lookup.Title = displayName;
                }

                lookup.Update(true);

                return lookup;
            }

            return null;
        }

        /// <summary>
        /// The create list lookup field.
        /// </summary>
        /// <param name="displayName">
        /// The display name.
        /// </param>
        /// <param name="fieldName">
        /// The field name.
        /// </param>
        /// <param name="group">
        /// The group.
        /// </param>
        /// <param name="required">
        /// The required.
        /// </param>
        /// <param name="allowMultipleValues">
        /// The allow multiple values.
        /// </param>
        /// <param name="listWebUrl">
        /// The list Web Url.
        /// </param>
        /// <param name="listName">
        /// The list name.
        /// </param>
        /// <param name="lookupListWebUrl">
        /// The lookup List Web Url.
        /// </param>
        /// <param name="lookupListName">
        /// The lookup list name.
        /// </param>
        /// <param name="lookupField">
        /// The lookup field.
        /// </param>
        /// <returns>
        /// An instance of the newly created lookup field
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// </exception>
        public static SPFieldLookup CreateListLookupField(string displayName, string fieldName, string group, bool required, bool allowMultipleValues, string listWebUrl, string listName, string lookupListWebUrl, string lookupListName, string lookupField)
        {
            SPLogger.LogToDeveloper(MethodBase.GetCurrentMethod().Name);

            SPFieldLookup lookup;

            using (SPSite listSite = new SPSite(listWebUrl))
            {
                using (SPWeb listWeb = listSite.OpenWeb())
                {
                    using (SPSite lookupListSite = new SPSite(lookupListWebUrl))
                    {
                        using (SPWeb lookupListWeb = lookupListSite.OpenWeb())
                        {
                            SPList list = SPListHelper.GetList(listWeb, listName);
                            SPList lookupList = SPListHelper.GetList(lookupListWeb, lookupListName);

                            if (list == null)
                            {
                                throw new ArgumentOutOfRangeException("listName", "Cannot find list with name " + listName);
                            }

                            if (lookupList == null)
                            {
                                throw new ArgumentOutOfRangeException("lookupListName", "Cannot find list with name " + lookupListName);
                            }

                            string internalName = list.Fields.AddLookup(fieldName, lookupList.ID, lookupListWeb.ID, required);

                            lookup = list.Fields.GetFieldByInternalName(internalName) as SPFieldLookup;

                            if (lookup != null)
                            {
                                lookup.AllowMultipleValues = allowMultipleValues;
                                lookup.LookupField = lookupField;
                                lookup.Group = group;

                                // Make the first item on the list the default value
                                lookup.DefaultValue = "1;#";
                                if (!String.IsNullOrEmpty(displayName))
                                {
                                    lookup.Title = displayName;
                                }

                                lookup.Update(true);
                            }
                        }
                    }
                }
            }

            return lookup;
        }

        /// <summary>
        /// Creates a new lookup field and adds it to a content type.
        /// </summary>
        /// <param name="displayName">
        /// The display name to be given to the field
        /// </param>
        /// <param name="fieldName">
        /// Name of the fields to create
        /// </param>
        /// <param name="group">
        /// Name of the field group to add the field to
        /// </param>
        /// <param name="required">
        /// Is this a required field
        /// </param>
        /// <param name="allowMultipleValues">
        /// Does the field allow for multiple values
        /// </param>
        /// <param name="contentTypeWeb">
        /// The content Type Web.
        /// </param>
        /// <param name="listWeb">
        /// The list Web.
        /// </param>
        /// <param name="lookupListName">
        /// The name of the list used by the lookup field
        /// </param>
        /// <param name="lookupField">
        /// The name of the field used by the lookup field
        /// </param>
        /// <param name="contentType">
        /// The content type where the new lookup field will be added 
        /// </param>
        /// <returns>
        /// A reference to the newly created lookup field
        /// </returns>
        public static SPFieldLookup CreateLookupContentTypeField(string displayName, string fieldName, string group, bool required, bool allowMultipleValues, SPWeb contentTypeWeb, SPWeb listWeb, string lookupListName, string lookupField, string contentType)
        {
            SPLogger.LogToDeveloper(MethodBase.GetCurrentMethod().Name);

            SPFieldLookup field = CreateLookupField(displayName, fieldName, group, required, allowMultipleValues, contentTypeWeb, listWeb, lookupListName, lookupField);

            LinkFieldToContentType(contentTypeWeb, contentType, field);

            return field;
        }

        /// <summary>
        /// Creates a new lookup field, adds it to a content type and adds it to a list view.
        /// </summary>
        /// <param name="displayName">
        /// The display name to be given to the field
        /// </param>
        /// <param name="fieldName">
        /// Name of the fields to create
        /// </param>
        /// <param name="group">
        /// Name of the field group to add the field to
        /// </param>
        /// <param name="required">
        /// Is this a required field
        /// </param>
        /// <param name="allowMultipleValues">
        /// Does the field allow for multiple values
        /// </param>
        /// <param name="contentTypeWeb">
        /// The SPWeb where the field will be created
        /// </param>
        /// <param name="listWeb">
        /// The list Web.
        /// </param>
        /// <param name="lookupListName">
        /// The name of the list used by the lookup field
        /// </param>
        /// <param name="lookupField">
        /// The name of the field used by the lookup field
        /// </param>
        /// <returns>
        /// A reference to the newly created lookup field
        /// </returns>
        public static SPFieldLookup CreateLookupField(string displayName, string fieldName, string group, bool required, bool allowMultipleValues, SPWeb contentTypeWeb, SPWeb listWeb, string lookupListName, string lookupField)
        {
            SPLogger.LogToDeveloper(MethodBase.GetCurrentMethod().Name);

            SPList lookupList = SPListHelper.GetList(listWeb, lookupListName);

            string internalName = contentTypeWeb.Fields.AddLookup(fieldName, lookupList.ID, listWeb.ID, required);

            var lookup = contentTypeWeb.Fields.GetFieldByInternalName(internalName) as SPFieldLookup;

            if (lookup != null)
            {
                lookup.AllowMultipleValues = allowMultipleValues;
                lookup.LookupField = lookupField;
                lookup.Group = group;

                // Make the first item on the list the default value
                lookup.DefaultValue = "1;#";
                if (!String.IsNullOrEmpty(displayName))
                {
                    lookup.Title = displayName;
                }

                lookup.Update(true);
            }

            return lookup;
        }

        /// <summary>
        /// Associates a field to a content type
        /// </summary>
        /// <param name="web">
        /// The web.
        /// </param>
        /// <param name="contentType">
        /// Type of the content.
        /// </param>
        /// <param name="field">
        /// The field.
        /// </param>
        public static void LinkFieldToContentType(SPWeb web, string contentType, SPField field)
        {
            SPLogger.LogToDeveloper(MethodBase.GetCurrentMethod().Name);

            SPContentType ct = web.ContentTypes[contentType];
            ct.FieldLinks.Add(new SPFieldLink(field));
            ct.Update(true);
        }

        /// <summary>
        /// Associates a field to a content type
        /// </summary>
        /// <param name="web">
        /// The web.
        /// </param>
        /// <param name="contentType">
        /// Type of the content.
        /// </param>
        /// <param name="fieldName">
        /// The field Name.
        /// </param>
        public static void LinkFieldToContentType(SPWeb web, string contentType, string fieldName)
        {
            SPLogger.LogToDeveloper(MethodBase.GetCurrentMethod().Name);

            SPField field = web.Fields.GetFieldByInternalName(fieldName);

            SPContentType ct = web.ContentTypes[contentType];
            ct.FieldLinks.Add(new SPFieldLink(field));
            ct.Update(true);
        }

        #endregion
    }
}
